package com.dd.common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.lionsoul.ip2region.xdb.Searcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import eu.bitwalker.useragentutils.UserAgent;
public class IpUtils {

    private static final Logger logger = LoggerFactory.getLogger(IpUtils.class);

    // 免费公开的根据 IP 查地址的 API
    private static final String IP_URL = "https://whois.pconline.com.cn/ipJson.jsp";

    // 腾讯地图 API 模板（key 应通过配置注入，不要硬编码）
    private static final String formatUrlTemplate = "https://apis.map.qq.com/ws/location/v1/ip?ip=%s&key=%s";
    private static final String tencentMapKey = YmlUtils.get("tencent.map.key");
    private static final String LOCAL_IP = "127.0.0.1";
    private static final String UNKNOWN = "未知";

    // ip2region 数据库文件名
    private static final String RESOURCE_NAME = "ip2region.xdb";

    private static Searcher searcher;

    static {
        byte[] cBuff;
        try (InputStream is = IpUtils.class.getClassLoader().getResourceAsStream(RESOURCE_NAME)) {
            if (is == null) {
                logger.error("无法加载资源文件: {}", RESOURCE_NAME);
            } else {
                // cBuff = is.readAllBytes();
                // 使用 ByteArrayOutputStream 替代 readAllBytes 方法以提高兼容性
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                int nRead;
                byte[] data = new byte[1024];
                while ((nRead = is.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                buffer.flush();
                cBuff = buffer.toByteArray();

                try {
                    searcher = Searcher.newWithBuffer(cBuff);
                    logger.info("ip2region 加载成功，支持离线 IP 定位");
                } catch (Exception e) {
                    logger.error("初始化 ip2region 查询器失败", e);
                }
            }
        } catch (IOException e) {
            logger.error("读取 ip2region.xdb 文件失败", e);
        }
    }



    /**
     * 获取当前请求对象
     */
    public static HttpServletRequest getRequest() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getRequest() : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取客户端真实 IP 地址
     */
    public static String getIp() {
        HttpServletRequest request = getRequest();
        if (request == null) {
            return LOCAL_IP;
        }

        String ip = request.getHeader("x-forwarded-for");
        if (isInvalidIp(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (isInvalidIp(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (isInvalidIp(ip)) {
            ip = request.getRemoteAddr();
        }

        if ("0:0:0:0:0:0:0:1".equals(ip) || "127.0.0.1".equals(ip)) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                ip = LOCAL_IP;
            }
        }

        // 多个 IP 时取第一个
        if (ip != null && ip.contains(",")) {
            String[] ips = ip.split(",");
            for (String str : ips) {
                str = str.trim();
                if (isValidPublicIp(str)) {
                    return str;
                }
            }
            return ips[0].trim();
        }

        return ip;
    }

    private static boolean isInvalidIp(String ip) {
        return ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip);
    }

    private static boolean isValidPublicIp(String ip) {
        return ip != null && !ip.isEmpty() && !ip.startsWith("127.") && !ip.startsWith("192.168.") && !ip.startsWith("10.") && !ip.startsWith("172.16.");
    }

    /**
     * 使用 ip2region 离线数据库解析 IP 地理信息
     * 格式：国家|省份|城市|ISP运营商
     */
    public static String getIp2region(String ip) {
        if (searcher == null) {
            logger.warn("ip2region 未初始化，无法查询 IP: {}", ip);
            return UNKNOWN;
        }
        if (isInvalidIp(ip) || LOCAL_IP.equals(ip)) {
            return "本机地址";
        }
        try {
            String region = searcher.search(ip);
            if (region != null) {
                region = region.replace("|0", "").replace("0|", "").replace("内网IP|内网IP", "局域网");
                return region.isEmpty() ? UNKNOWN : region;
            }
        } catch (Exception e) {
            logger.warn("ip2region 查询失败，IP: {}", ip, e);
        }
        return UNKNOWN;
    }

    /**
     * 通过腾讯地图 API 在线解析 IP（作为 fallback）
     * 注意：key 应从配置传入，不要硬编码
     */
    public static String analyzeIp(String ip, String tencentKey) {
        if (isInvalidIp(ip) || LOCAL_IP.equals(ip)) {
            return "{\"status\":1,\"message\":\"invalid ip\"}";
        }
        String urlStr = String.format(formatUrlTemplate, ip, tencentKey);
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(urlStr);
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(5000);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; IpUtils)");

            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
            }
        } catch (Exception e) {
            logger.warn("腾讯 IP 定位 API 调用失败，IP: {}", ip, e);
            return "{\"status\":1,\"message\":\"request failed\"}";
        }
        return result.toString();
    }

    /**
     * 解析腾讯 API 响应 JSON
     */
    private static String parseTencentResponse(String json) {
        try {
            JSONObject root = JSON.parseObject(json);
            if (root == null || root.getIntValue("status") != 0) {
                return "中国-未知-未知";
            }

            JSONObject result = root.getJSONObject("result");
            if (result == null) return "中国-未知-未知";

            JSONObject adInfo = result.getJSONObject("ad_info");
            if (adInfo == null) return "中国-未知-未知";

            String nation   = getString(adInfo, "nation",   "中国");
            String province = getString(adInfo, "province", "未知");
            String city     = getString(adInfo, "city",     "未知");

            return nation + "-" + province + "-" + city;
        } catch (Exception e) {
            e.printStackTrace();
            return "中国-未知-未知";
        }
    }

    private static String getString(com.alibaba.fastjson2.JSONObject obj, String key, String defaultValue) {
        String value = obj.getString(key);
        return (value == null || value.trim().isEmpty()) ? defaultValue : value.trim();
    }

    /**
     * 解析 IP 获取城市信息（优先使用 ip2region）
     */
    public static String getCityInfo(String ip) {
        // 1. 优先使用 ip2region
        String region = getIp2region(ip);
        if (!UNKNOWN.equals(region) && !region.contains(UNKNOWN)) {
            return region.replace("|", "-");
        }
        // 2. fallback 到腾讯 API（需传入 key）
        if (tencentMapKey != null && !tencentMapKey.isEmpty()) {
            String jsonResponse = analyzeIp(ip, tencentMapKey);
            return parseTencentResponse(jsonResponse);
        }

        return "中国-未知-未知";
    }


    /**
     * 获取服务器本地 IP
     */
    public static String getHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return LOCAL_IP;
        }
    }

    /**
     * 获取服务器主机名
     */
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            return UNKNOWN;
        }
    }

    // 可添加 parseTencentResponse 解析腾讯返回 JSON 的方法（建议用 POJO）

    public static void main(String[] args) {
        System.out.println("本地 IP: " + getHostIp());
        System.out.println("本地主机名: " + getHostName());
        System.out.println("测试 IP 定位: " + getIp2region("58.20.50.137"));
    }
}
